﻿// /////////////////////////////////////////////////////////////////////
// 
//  Codeplex JSAnalyse
//  Copyright (c) 2011
//  JSAnalyse.Core   DependencyAnalyser.cs
// 
// /////////////////////////////////////////////////////////////////////
using System.Collections.Generic;
using System.Linq;
using JSAnalyse.Core.Interfaces;

namespace JSAnalyse.Core.Analyser
{
    internal class DependencyAnalyser
    {
        #region Private Variables
        private AnalyserInput _currentFile;
        private List<AnalyserInput> _possibleDependentFiles;
        private IAllowedDependencies _allowedDependencies;
        #endregion

        #region Constructor

        /// <summary>
        /// Initializes a new instance of the <see cref="DependencyAnalyser"/> class.
        /// </summary>
        /// <param name="allowedDependencies">The allowed dependencies.</param>
        /// <param name="currentFile">The current file to analyse</param>
        /// <param name="possibleDependentFiles">The possible dependent files.</param>
        public DependencyAnalyser(IAllowedDependencies allowedDependencies, AnalyserInput currentFile, List<AnalyserInput> possibleDependentFiles)
        {
            _currentFile = currentFile;
            _possibleDependentFiles = possibleDependentFiles;
            _allowedDependencies = allowedDependencies;
        }
        #endregion

        #region Public Methods

        /// <summary>
        /// Starts the analyses for the files in context
        /// </summary>
        /// <returns>dependency analyses</returns>
        public DependencyAnalysisResult Analyse()
        {
            var result = new DependencyAnalysisResult();
            foreach (var callDependency in _currentFile.CallDependencies)
            {
                result.AppendResult(SearchDependencies(callDependency));
            }
            return result;
        }
        #endregion

        #region Private Methods
        private DependencyAnalysisResult SearchDependencies(CallDependencyInfo callDependency)
        {
            var result = new DependencyAnalysisResult();
            foreach (var possibleDependencies in _possibleDependentFiles)
            {
                bool isDependend = HasDependencies(callDependency, possibleDependencies);
                if (isDependend)
                {
                    var dependencyInfo = new DependencyInfo(possibleDependencies.SourceFile, callDependency.MemberSourceLocation.Line, callDependency.MemberSourceLocation.Character);
                    result.FileDependencies.Add(dependencyInfo);
                    if (!_allowedDependencies.IsAllowed(_currentFile.SourceFile, possibleDependencies.SourceFile))
                    {
                        result.WrongFileDependencies.Add(dependencyInfo);                
                    }
                }
            }
            return result;
        }

        /// <summary>
        /// Determines whether the specified call dependency has dependencies.
        /// </summary>
        /// <param name="callDependency">The call dependency.</param>
        /// <param name="possibleDependencies">The possible dependencies.</param>
        /// <returns><c>true</c> if the specified call dependency has dependencies; otherwise, <c>false</c>.</returns>
        /// <remarks></remarks>
        private bool HasDependencies(CallDependencyInfo callDependency, AnalyserInput possibleDependencies)
        {
            return possibleDependencies.Declarations.Any(possibleDependency => possibleDependency.Identifier.ClassName == callDependency.Identifier.ClassName &&
                (string.IsNullOrEmpty(possibleDependency.Identifier.Member) || possibleDependency.Identifier.Member == callDependency.Identifier.Member));
        }

        #endregion
    }
}
